package vip.manda.framework.web;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Validator;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import vip.manda.framework.auth.AuthRepository;
import vip.manda.framework.auth.HttpManager;
import vip.manda.framework.auth.TokenManager;
import vip.manda.framework.bean.BeanFactory;
import vip.manda.framework.data.DataType;
import vip.manda.framework.data.repository.impl.BaseRepositoryImpl;
import vip.manda.framework.log.Log;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.*;

/**
 * @author hongda.li 2022-04-13 16:22
 */
public class BaseController {

    private Map<String, String[]> params;
    private HttpServletRequest request;
    private HttpServletResponse response;
    private HttpSession session;
    private String jsonStr;
    public Log log;

    public HttpServletResponse getResponse(){
        return this.response;
    }
    public HttpServletRequest getRequest(){
        return this.request;
    }
    public HttpSession getSession(){
        return session;
    }
    public JSONObject getJsonObject(){
        return JSONUtil.parseObj(jsonStr);
    }
    public JSONArray getJsonArray(){
        return JSONUtil.parseArray(jsonStr);
    }
    public Map<String, Object> getTable(BaseRepositoryImpl repository){
        Map<String, DataType> columns = repository.getColumns();
        Map<String, Object> result = new HashMap<>(columns.size());
        columns.forEach((key, value) -> {
            switch (value) {
                case INTEGER:
                    result.put(key, getInt(key));
                    break;
                case TEXT:
                    result.put(key, getStr(key));
                    break;
                case REAL:
                    result.put(key, getDouble(key));
                    break;
                default:
            }
        });
        return result;
    }

    public List<String> getList(String name){
        notNull(name);
        return Convert.toList(String.class, params.get(name));
    }

    public double getDouble(String name){
        notNull(name);
        return Convert.toDouble(getStr(name));
    }

    public long getLong(String name){
        notNull(name);
        return Convert.toLong(getStr(name));
    }

    public boolean getBool(String name){
        notNull(name);
        return Convert.toBool(getStr(name));
    }
    public int getInt(String name){
        notNull(name);
        return Convert.toInt(getStr(name));
    }

    public String getStr(String name){
        return params.get(name)[0];
    }

    public void notNull(String name){
        Assert.notNull(name);
    }

    public void notEmpty(String name){
        Assert.notEmpty(getStr(name));
    }

    public void notNull(String... names){
        for (String name : names) {
            Assert.notNull(params.get(name));
        }
    }

    public void isEmail(String name){
        Assert.isTrue(Validator.isEmail(getStr(name)));
    }

    public void isChinese(String name){
        Assert.isTrue(Validator.isChinese(getStr(name)));
    }

    public void containChinese(String name){
        Assert.isTrue(Validator.hasChinese(getStr(name)));
    }

    public void isNumber(String name){
        Assert.isTrue(Validator.isNumber(getStr(name)));
    }

    public void containNumber(String name){
        Assert.isTrue(Validator.hasNumber(getStr(name)));
    }

    public void isLowerCase(String name){
        Assert.isTrue(Validator.isLowerCase(getStr(name)));
    }

    public void isUpperCase(String name){
        Assert.isTrue(Validator.isUpperCase(getStr(name)));
    }

    public void isUrl(String name){
        Assert.isTrue(Validator.isUrl(getStr(name)));
    }

    public void isBirthday(String name){
        Assert.isTrue(Validator.isBirthday(name));
    }

    public void isBetween(String name, int min, int max){
        Assert.isTrue(Validator.isBetween(getInt(name), min, max));
    }

    public void isPhone(String name){
        Assert.isTrue(Validator.isMobile(getStr(name)));
    }
    public void hasPermissions(String... permissions){
        String login = getLogin();
        AuthRepository repository = BeanFactory.getContainer().getBean(AuthRepository.class);
        List<String> list = repository.get(login);
        if (!new HashSet<>(list).containsAll(Arrays.asList(permissions))){
            log.debug("No permission to access[{}]", login);
            throw new RuntimeException("No permission");
        }
    }

    public void setLogin(String loginId){
        Assert.notNull(request);
        String token = TokenManager.createToken(loginId);
        log.info("Create access_token[{}][{}]", loginId, token);
        HttpManager.setAccessToken(token, response);
    }

    public String getLogin(){
        Assert.notNull(request);
        String accessToken = HttpManager.getAccessToken(request);
        log.info("Parse access_token[{}]", accessToken);
        return TokenManager.getTokenValue(accessToken);
    }

    public boolean checkLogin(){
        Assert.notNull(request);
        String accessToken = HttpManager.getAccessToken(request);
        log.info("Verify access_token[{}]", accessToken);
        return TokenManager.verifyToken(accessToken);
    }

    public void isLogin(){
        Assert.isTrue(checkLogin());
    }

    public void offLogin(){
        log.info("Clear access_token");
        HttpManager.clearAccessToken(response);
    }

    public void refreshLogin(){
        log.info("Refresh access_token");
        HttpManager.setAccessToken(TokenManager.createToken(getLogin()), response);
    }
}
